using System;
using System.Collections.Generic;
using AntEater.ComponentModel.Validation;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace AntEater.ComponentModel.BuildElements
{

    /// <summary>
    /// Provides an base implementation for container build elements.
    /// </summary>
    [Serializable]
    [ChildBuildElementType(typeof(CommentBuildElement))]
    public abstract class ContainerBuildElementBase : BuildElementBase, IContainerBuildElement
    {

        /// <summary>
        /// Initializes a new instance of the <see cref="T:ContainerBuildElementBase"/> class.
        /// </summary>
        /// <param name="context">The context.</param>
        protected ContainerBuildElementBase(BuildFileDefinition context)
            : base(context) {
            this._childElements = new BuildElementCollection(this);
            this._childElements.CollectionChanged += new EventHandler<CollectionChangeEventArgs>(ChildElementsCollectionChanged);
        }

        private BuildElementCollection _childElements;

        /// <summary>
        /// Gets the child elements.
        /// </summary>
        /// <value>The child elements.</value>
        [Browsable(false)]
        public BuildElementCollection ChildElements {
            get { return _childElements; }
        }

        /// <summary>
        /// Determines whether this instance is valid.
        /// </summary>
        /// <value></value>
        /// <returns>
        /// 	<c>true</c> if this instance is valid; otherwise, <c>false</c>.
        /// </returns>
        public abstract override bool IsValid {
            get;
        }

        /// <summary>
        /// Determines whether an instance of the specified build element type can be inserted.
        /// </summary>
        /// <param name="buildElementType">Type of the build element.</param>
        /// <returns>
        /// 	<c>true</c> if an instance of the specified build element type can be inserted; otherwise, <c>false</c>.
        /// </returns>
        public bool CanInsert(Type buildElementType) {
            bool canInsert = false;
            
            ChildBuildElementTypeAttribute[] attributes
                 = AntEater.ComponentModel.Utilities.GetTypeAttributesFromObject<ChildBuildElementTypeAttribute>(this);


            if (attributes != null && attributes.Length > 0) {
                foreach (ChildBuildElementTypeAttribute attribute in attributes) {
                    if (attribute.BuildElementType == buildElementType) {
                        if (attribute.MaxCount != -1) {
                            int occurrence = 0;

                            foreach (IBuildElement element in this.ChildElements) {
                                if (element.GetType() == buildElementType) {
                                    occurrence++;
                                }
                            }
                            if (occurrence < attribute.MaxCount) {
                                canInsert = true;
                                break;
                            }
                        }
                        else {
                            canInsert = true;
                            break;
                        }
                    }
                }
            }

            return canInsert;
        }

        /// <summary>
        /// Validates the specified recursive.
        /// </summary>
        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
        /// <returns></returns>
        public abstract override ReadOnlyCollection<ValidationResult> Validate(bool recursive);

        /// <summary>
        /// Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>
        /// A new object that is a copy of this instance.
        /// </returns>
        public override object Clone() {
            ContainerBuildElementBase newElement = base.Clone() as ContainerBuildElementBase;

            newElement._childElements.AddRange(this._childElements.Clone() as BuildElementCollection); 

            return newElement;
        }

        /// <summary>
        /// Determines whether the child elements are valid.
        /// </summary>
        /// <returns>
        /// 	<c>true</c> if the child elements are valid; otherwise, <c>false</c>.
        /// </returns>
        protected bool AreChildElementsValid() {

            bool isValid = true;
            
            //check if all child elements
            foreach (IBuildElement element in _childElements) {
                isValid &= element.IsValid;
            }

            return isValid;
        }

        /// <summary>
        /// Childs the elements collection changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="T:System.ComponentModel.CollectionChangeEventArgs"/> instance containing the event data.</param>
        private void ChildElementsCollectionChanged(object sender, CollectionChangeEventArgs e) {
            this.OnPropertyChanged("ChildElements");
        }
    }
}
